#include "file_task.h"
#include "file_uploader.h"

#include "public_define.h"
#include "fileReupload.h"
#include "file_upload_status.h"
#include "data_cache.h"
#include "event_reupload.h"
#include "filemanagercommand.h"
#include "httpagent_com.h"
#include "apicom_userset.h"
#include "user_agent_file_S3.h"
#include "user_agent_http.h"


using namespace DcAdr;

std::set<string> FgEventSet = {
    "BA528",
    "BA530",
    "BA531",
    "BA532",
    "IT003",
    "IT574",
    "IT575",
    "IT576",
    "IT004",
    "IT561",
    "IT577"};


FileTask::FileTask()
{
}

FileTask::~FileTask()
{
}

void FileTask::setFileUploadParam(const FileUploadParam &info)
{
    fileParam.taskId = info.taskId;
    fileParam.fileName = info.fileName;
    fileParam.filePath = info.filePath;
    fileParam.businessType=info.businessType;
}

//state 1：开始上传  2：结束上传;
//result 0:成功  -1 失败
void FileTask::speedStatistics(const std::string &filePath, int state, int result)
{
    struct stat s_buf;
    int ret = stat(filePath.c_str(), &s_buf); 
    (void)ret;

    time_t timep;
    time(&timep);
    tm *p = localtime(&timep);
    if (p == nullptr)
    {
        return;
    }
    static time_t start = 0;
    if (1 == state)
    {
        start = timep;
        Log_Info("[upload_statistics]start to upload file:{}; size:{} MB; nowtime:{}-{}-{} {}:{}:{}", filePath,  to_string(((double)s_buf.st_size)/(1024 * 1024)), 
            (int)((1900 + p->tm_year) % 100), (int)(1 + p->tm_mon), (int)p->tm_mday, (int)p->tm_hour, (int)p->tm_min, (int)p->tm_sec);
    }
    else
    {
        time_t during = timep - start;
        if (result == 0)
        {
            Log_Info("[upload_statistics]end to upload; success file:{};  size:{} MB; during:{} s; nowtime:{}-{}-{} {}:{}:{}", filePath, to_string(((double)s_buf.st_size)/(1024 * 1024)), during,
                (int)((1900 + p->tm_year) % 100), (int)(1 + p->tm_mon), (int)p->tm_mday, (int)p->tm_hour, (int)p->tm_min, (int)p->tm_sec);
        }
        else
        {
            Log_Info("[upload_statistics]end to upload; faild file:{};  size:{} MB; during:{} s; nowtime:{}-{}-{} {}:{}:{}", filePath, to_string(((double)s_buf.st_size)/(1024 * 1024)), during,
                (int)((1900 + p->tm_year) % 100), (int)(1 + p->tm_mon), (int)p->tm_mday, (int)p->tm_hour, (int)p->tm_min, (int)p->tm_sec);
        }
    }
}

void FileTask::removeNoFgDat(const std::string &filePath)
{
    if (CommonOprString::childStrContainCheck(filePath, "/ds/datacollect/") != DC_SUCC)
    {
        return;
    }

    std::string bascName = Util::getFileBaseName(filePath);
    std::string eventCode = DataRecord::getEvtFromDat(bascName);

    if (!eventCode.compare("IT031"))//默认的这个就认为转化不成功
    {
        Log_Info("getEvtFromDat faild");
        return;
    }
    Log_Info("removeNoFgDat eventCode: {} end, fileName : {}", eventCode, bascName);

    //是拉取的adr录制的dat文件，传成功就删本地的
    if (bascName.find(".dat") != std::string::npos)
    {
        //非法规要求的事件，删除
        if (FgEventSet.find(eventCode) == FgEventSet.end())
        {
            auto func = [=]()
            {
                FileManagerCommand::getInstance()->delFileUploadSuccess(filePath);
            };
            appendEvent(ThreadType::E_InFileCacehThread, func);
            // if (remove(fileName.c_str()))
            // {
            //     Log_Info("remove yingdi vedio faild;");
            // }
        }
    }

}

bool FileTask::certificateExistJudge()
{
    std::string tuidPath = global_data::g_tuid_path;
    std::string rootcaPath = global_data::g_rootca_cert;
    std::string clientPath = global_data::g_http_ca_path + global_data::g_client_cert;
    std::string privatePath = global_data::g_http_ca_path + global_data::g_client_key;

    bool ret = true;

    // TUID.txt
    if (0 != access(tuidPath.c_str(),F_OK))
    {
        fileUploadStatus(fileParam, FileUpLoadStatus_t::TUID_NOT_EXIST);
        ret = false;
    }

    // rootca.cer
    if (0 != access(rootcaPath.c_str(),F_OK))
    {
        fileUploadStatus(fileParam, FileUpLoadStatus_t::ROOTCA_CER_NOT_EXIST);
        ret = false;
    }

    // client.cer
    if (0 != access(clientPath.c_str(),F_OK))
    {
        fileUploadStatus(fileParam, FileUpLoadStatus_t::CLIENT_CER_NOT_EXIST);
        ret = false;
    }

    // private.key
    if ((0 != access(privatePath.c_str(),F_OK)) && (global_data::g_client_keyBuff.size() == 0))
    {
        fileUploadStatus(fileParam, FileUpLoadStatus_t::PRIVATE_KEY_NOT_EXIST);
        ret = false;
    }
    return ret;
}

void FileTask::fileUploadStatus(const FileUploadParam &info, const uint32_t &fileuploadstatus)
{
    std::string taskId = info.taskId;
    if (!taskId.empty())
    {   
        FileUploadStatus::getInstance().FileUploadStatus_send(info, fileuploadstatus);
        Log_Info("[FileTask] [fileUploadStatus] fileuploadstatus: {}", fileuploadstatus);
    }
}

void my_http_log_callback(const string &str)
{
    string logstr = string(str);
    Log_Info(logstr);
}

void FileTask::s3_upload(const FileUploadParam &fileup)
{
    Log_Info("s3_upload");
    // 设置文件上传参数
    setFileUploadParam(fileup);
	
	T_SdkInit paramSdk;
	//1.设置证书路径
	paramSdk.cerset.vinFile = global_data::g_car_vin;
	paramSdk.cerset.tuidFile = global_data::g_tuid_path;
	paramSdk.cerset.userRootCaCer = global_data::g_SdaCaFilePath + global_data::g_rootCaCertPem;
	paramSdk.cerset.factoryRootCaCer = global_data::g_httpCaFilePath + global_data::g_rootCaCertPem;
	paramSdk.cerset.clientKeyBuff = global_data::g_client_keyBuff;
	paramSdk.cerset.clientCer = global_data::g_http_ca_path + global_data::g_client_cert;
	paramSdk.cerset.clientKey = global_data::g_http_ca_path + global_data::g_client_key;
	Log_Info("cer.vinFile:{},cer.tuidFile:{},cer.userRootCaCer:{},cer.factoryRootCaCer:{},cer.clientCer:{},cer.clientKey:{}",
	paramSdk.cerset.vinFile,paramSdk.cerset.tuidFile,paramSdk.cerset.userRootCaCer,paramSdk.cerset.factoryRootCaCer,
	paramSdk.cerset.clientCer,paramSdk.cerset.clientKey);

	//2.设置云平台环境
	if(global_data::g_cloudNetPrefix ==STR_PREEVN)
	{
		paramSdk.caplatNum = CLOUD_CHINA_PRED;
	}
	else if(global_data::g_cloudNetPrefix ==STR_DEVEVN)
	{
		paramSdk.caplatNum = CLOUD_CHINA_PROD;
	}
	else
	{
		Log_Info("global_data::g_cloudNetPrefix:{}",global_data::g_cloudNetPrefix);
		paramSdk.caplatNum = CLOUD_CHINA_PROD;
	}

	paramSdk.controllerCode = global_data::g_controler_code;
	paramSdk.sdkAutoEncryptFlag = false;
	paramSdk.workDir = "";   // 必填字段：SDK临时使用目录，用于加密过程中存储临时文件，需预留足够空间
	paramSdk.curlLogFlag = false;
	paramSdk.on_log = my_http_log_callback;
	ApicomUserSet::sdkInit(paramSdk);
#if 0

    // 为HTTPAPI模块设置日志打印回调函数
     ApicomUserSet::userSetHttpLogCallback(my_http_log_callback);
    // ApicomUserSet::userSetCurlLog(true);
    T_CerSet cerPath;
    //1.设置证书路径
    cerPath.tuidFile = global_data::g_tuid_path;
    cerPath.rootCaCerPath = global_data::g_SdaCaFilePath;
    cerPath.rootCaCertPem = global_data::g_rootCaCertPem;
    if (!CommonOprSystem::isPathExist(cerPath.rootCaCerPath+cerPath.rootCaCertPem))
    {
        cerPath.rootCaCerPath = global_data::g_httpCaFilePath;
        cerPath.rootCaCertPem = global_data::g_rootCaCertPem;
    }
    cerPath.factoryCaCerPath =global_data::g_httpCaFilePath;
    //cerPath.rootCaCertPem=cerPath.rootCaCerPath;
    cerPath.clientKeyBuff = global_data::g_client_keyBuff;
    cerPath.clientCer = global_data::g_http_ca_path + global_data::g_client_cert;
    cerPath.clientKey =global_data::g_http_ca_path + global_data::g_client_key;
    Log_Info("cerPath.tuidFile:{},cerPath.rootCaCerPath:{},cerPath.rootCaCertPem:{},cerPath.factoryCaCerPath;{},cerPath.clientCer:{},cerPath.clientKey:{}",cerPath.tuidFile,cerPath.rootCaCerPath,cerPath.rootCaCertPem,cerPath.factoryCaCerPath,cerPath.clientCer,cerPath.clientKey);
    ApicomUserSet::userSetCaCer(cerPath);
    //2.设置云平台环境
    if(global_data::g_cloudNetPrefix ==STR_PREEVN)
    {
        ApicomUserSet::userSetCloudCaplatform(CLOUD_CHINA_PRED);
    }
    else if(global_data::g_cloudNetPrefix ==STR_DEVEVN)
    {
        ApicomUserSet::userSetCloudCaplatform(CLOUD_CHINA_PROD);
    }
    else
    {
        Log_Info("global_data::g_cloudNetPrefix:{}",global_data::g_cloudNetPrefix);
    }
    Log_Info("global_data::g_cloudNetPrefix:{}",global_data::g_cloudNetPrefix);
	#endif
    //3.设置上传文件的文件名，文件路径，事件名
		
    T_UserReqFileS3 reqInfo;

    reqInfo.fileNameFull =fileup.filePath;
    reqInfo.businessType =fileup.businessType;
    reqInfo.controllerCode = global_data::g_controler_code;
    reqInfo.extraParam["eventCode"] = fileup.eventCode;
    reqInfo.extraParam["taskId"] = fileup.taskId;
	Log_Info("businessType:{},controllerCode:{}",reqInfo.businessType,reqInfo.controllerCode);
    reqInfo.extraParam["filePath"] = fileup.filePath;
    //reqInfo.extraParam["controllerCode"] = global_data::g_controler_code;
    //如果是三段式文件上次用doHttpFileUpload，传参数也不一样
    //T_FileReqInfo fileReqInfo;
    //fileReqInfo.fileName=fileup.filePath;
    //fileReqInfo.taskID=fileup.taskId;
	
    //4.调用上传接口进行上传
    if(1)
    {

        E_S3FileRlt res =  UserAgentFileS3::getInstance().doS3FileUpload(reqInfo);
        //E_FileReqRlt resReqRlt = HttpAgentFile::getInstance().doHttpFileUpload(fileReqInfo);
        Log_Info("E_S3FileRlt:{}",res);
        //Log_Info("resReqRlt:{}",resReqRlt);
        switch (res)
        {
            case S3_FILE_ERR_SUCCESS:
            {
                //FileReupload::getInstance().dealUploadResult(fileParam.filePath, 0);
                Log_Info("[FileTask][upload] file upload success. fileName:{}", fileParam.fileName);
                // 上传文件成功
                fileUploadStatus(fileParam, FileUpLoadStatus_t::UPLOAD_FILE_SUCCESS);
                FileReupload::getInstance().dealUploadResult(fileParam.filePath, 0);

                // FC011事件会事件补发,成功后删除记录
                if (!fileup.eventCode.compare("FC011"))
                {
                    EventReupload::getInstance().deletEvtReupFile();
                }

                speedStatistics(fileParam.filePath, 2, 0);
                // 谭川那几个法规的事件文件传成功不删，其他传成功删
                removeNoFgDat(fileParam.filePath);
                        
                /* code */
                break;           
            }
            case S3_FILE_ERR_FILE_NOTEXIST:
            {
                Log_Info("[FileTask][upload] file upload faild S3_FILE_ERR_FILE_NOTEXIST. fileName:{}", fileParam.fileName);
                // 文件不存在
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_NOT_EXIST);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            case S3_FILE_ERR_FILE_EMPTY:
            {
                Log_Info("[FileTask][upload] file upload faild S3_FILE_ERR_FILE_EMPTY. fileName:{}", fileParam.fileName);
                // 文件为空
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_SIZE_EQUAL_ZERO);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            case S3_FILE_ERR_FILE_OVERSIZE:
            {
                Log_Info("[FileTask][upload] file upload faild S3_FILE_ERR_FILE_OVERSIZE. fileName:{}", fileParam.fileName);
                // 文件大小超限
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_SIZE_OVER_LIMIT);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            case S3_FILE_ERR_CERTLOSS:
            {
                Log_Info("[FileTask][upload] file upload faild S3_FILE_ERR_CERTLOSS. fileName:{}", fileParam.fileName);
                // 车机证书缺失
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::CLIENT_CER_NOT_EXIST);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            case S3_FILE_ERR_LINK_GET:
            {
                Log_Info("[FileTask][upload] file upload faild S3_FILE_ERR_LINK_GET. fileName:{}", fileParam.fileName);
                // 获取上传链接失败
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::GET_FILE_UPLOAD_LINK_ERROR);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            case S3_FILE_ERR_LINK_PARSE:
            {
                Log_Info("[FileTask][upload] file upload faild S3_FILE_ERR_LINK_PARSE. fileName:{}", fileParam.fileName);
                // 上传链接获取失败
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_UPLOAD_LINK_RESPONSE_DATA_PARSE_FAIL);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            // case S3_FILE_ERR_S3_INIT:
            // {
            //     Log_Info("[FileTask][upload] file upload faild. fileName:{}", fileParam.fileName);
            //     //s3 init失败
            //     // 文件上传响应数据解析失败
            //     fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_UPLOAD_RESPONSE_DATA_PARSE_FAIL);
            //     FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
            //     speedStatistics(fileParam.filePath, 2, -1);
            //     break;
            // }
            case S3_FILE_ERR_RLTACK:
            {
                Log_Info("[FileTask][upload] file upload faild S3_FILE_ERR_RLTACK. fileName:{}", fileParam.fileName);
                // 上传结果响应回复失败
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::SEND_FILE_UPLOAD_RESULT_REQUEST_FAIL);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }      
            default:
            {
                Log_Info("[FileTask][upload] file upload faild default. fileName:{}", fileParam.fileName);
                // 未知结果
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_UPLOAD_TIMEOUT_WAS_REACHED);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
                
        }
    }
    else
    {
    #if 0
        E_FileReqRlt resReqRlt = HttpAgentFile::getInstance().doHttpFileUpload(fileReqInfo);
        Log_Info("resReqRlt:{}",resReqRlt);
        switch (resReqRlt)
        {
            case FILE_ERR_SUCCESS:
            {
                //FileReupload::getInstance().dealUploadResult(fileParam.filePath, 0);
                Log_Info("[FileTask][upload] file upload success. fileName:{}", fileParam.fileName);
                // 上传文件成功
                fileUploadStatus(fileParam, FileUpLoadStatus_t::UPLOAD_FILE_SUCCESS);
                FileReupload::getInstance().dealUploadResult(fileParam.filePath, 0);

                // FC011事件会事件补发,成功后删除记录
                if (!fileup.eventCode.compare("FC011"))
                {
                    EventReupload::getInstance().deletEvtReupFile();
                }

                speedStatistics(fileParam.filePath, 2, 0);
                // 谭川那几个法规的事件文件传成功不删，其他传成功删
                removeNoFgDat(fileParam.filePath);
                        
                /* code */
                break;           
            }
            case FILE_ERR_FILE_NOTEXIST:
            {
                Log_Info("[FileTask][upload] file upload faild FILE_ERR_FILE_NOTEXIST. fileName:{}", fileParam.fileName);
                // 文件不存在
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_NOT_EXIST);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            case FILE_ERR_FILE_EMPTY:
            {
                Log_Info("[FileTask][upload] file upload faild FILE_ERR_FILE_EMPTY. fileName:{}", fileParam.fileName);
                // 文件为空
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_SIZE_EQUAL_ZERO);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            case FILE_ERR_FILE_OVERSIZE:
            {
                Log_Info("[FileTask][upload] file upload faild FILE_ERR_FILE_OVERSIZE. fileName:{}", fileParam.fileName);
                // 文件大小超限
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_SIZE_OVER_LIMIT);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            case FILE_ERR_CERTLOSS:
            {
                Log_Info("[FileTask][upload] file upload faild FILE_ERR_CERTLOSS. fileName:{}", fileParam.fileName);
                // 车机证书缺失
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::CLIENT_CER_NOT_EXIST);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            case FILE_ERR_LINK_GET:
            {
                Log_Info("[FileTask][upload] file upload faild FILE_ERR_LINK_GET. fileName:{}", fileParam.fileName);
                // 获取上传链接失败
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::GET_FILE_UPLOAD_LINK_ERROR);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            case FILE_ERR_LINK_PARSE:
            {
                Log_Info("[FileTask][upload] file upload faild FILE_ERR_LINK_PARSE. fileName:{}", fileParam.fileName);
                // 上传链接获取失败
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_UPLOAD_LINK_RESPONSE_DATA_PARSE_FAIL);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
            // case S3_FILE_ERR_S3_INIT:
            // {
            //     Log_Info("[FileTask][upload] file upload faild. fileName:{}", fileParam.fileName);
            //     //s3 init失败
            //     // 文件上传响应数据解析失败
            //     fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_UPLOAD_RESPONSE_DATA_PARSE_FAIL);
            //     FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
            //     speedStatistics(fileParam.filePath, 2, -1);
            //     break;
            // }
            case FILE_ERR_RLTACK:
            {
                Log_Info("[FileTask][upload] file upload faild FILE_ERR_RLTACK. fileName:{}", fileParam.fileName);
                // 上传结果响应回复失败
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::SEND_FILE_UPLOAD_RESULT_REQUEST_FAIL);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }      
            default:
            {
                Log_Info("[FileTask][upload] file upload faild default. fileName:{}", fileParam.fileName);
                // 未知结果
                // 文件上传响应数据解析失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_UPLOAD_TIMEOUT_WAS_REACHED);
                FileReupload::getInstance().dealUploadResult(fileup.filePath, -1);
                speedStatistics(fileParam.filePath, 2, -1);
                break;
            }
                
        }
	#endif
    }
    return;
}
void FileTask::upload(const FileUploadParam &fileup)
{
    // 设置文件上传参数
    setFileUploadParam(fileup);

    //开始准备传文件
    speedStatistics(fileParam.filePath, 1, 0);

    // 判断车端C2证书是否存在
    if (!certificateExistJudge())
    {
        // 证书不存在,删除事件补传任务文件
        EventReupload::getInstance().deletEvtReupFile();
        FileReupload::getInstance().dealUploadResult(fileParam.filePath, 0); // 证书不存在,删除文件信息
        Log_Info("[FileTask][upload] certificateExistJudge failed!");
        return;
    }

    // 判断文件是否存在
    if (!CommonOprSystem::isPathExist(fileParam.filePath))
    {
        // 文件不存在 
        fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_NOT_EXIST);
        FileReupload::getInstance().dealUploadResult(fileParam.filePath, 0); // 文件不存在，删除文件信息
        return;
    }

    Json::Value oneFile;
    if (!FileReupload::getInstance().readOneFileJson(fileParam.filePath, oneFile))
    {
        Log_Info("[FileTask][upload] readOneFileJson failed!");
        FileReupload::getInstance().dealUploadResult(fileParam.filePath, 0);
        return;
    }

    // 判断是否为分片文件
    if (!oneFile.isMember("isChunkFile"))
    {
        FileReupload::getInstance().dealUploadResult(fileParam.filePath, 0);
        Log_Info("[FileTask][upload] read isChunkFile failed!");
        return;
    }
    bool isChunkFile = JsonToValue<bool>(oneFile["isChunkFile"]);

    // 若为分片文件,读取curChunkTime和totalChunkTime字段
    int totalChunkTime = 0;
    int curChunkTime = 0;

    if (isChunkFile)
    {
        if (!oneFile.isMember("totalChunkTime") || !oneFile.isMember("curChunkTime"))
        {
            FileReupload::getInstance().dealUploadResult(fileParam.filePath, 0);
            Log_Info("[FileTask][upload] read totalChunkTime or curChunkTime failed!");
            return;
        }
        totalChunkTime = JsonToValue<int>(oneFile["totalChunkTime"]);
        curChunkTime = JsonToValue<int>(oneFile["curChunkTime"]);
    }

    // 上报文件开始上传状态,避免分片文件重复上报
    if (!isChunkFile || curChunkTime == 0)
    {
        fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_START_UPLOAD);
    }

    // 获取token
    if (!comoprhttp.httpReqInit(STR_DOMAIN_FILE))
    {
        Log_Info("[FileTask][upload] httpReqInit failed.");
        // 获取token失败
        fileUploadStatus(fileParam, FileUpLoadStatus_t::GET_TOKEN_ERROR);
        FileReupload::getInstance().dealUploadResult(fileParam.filePath, -1);
        speedStatistics(fileParam.filePath, 2, -1);
        return;
    }

    Log_Info("[FileTask][upload] comoprhttp.hu_tokenMsg: {}", comoprhttp.hu_tokenMsg);

    if (!comoprhttp.hu_tokenMsg.empty())
    {
        Json::Value extraJson;
        extraJson["controllerCode"] = global_data::g_controler_code;
        extraJson["fileName"] = fileParam.fileName;
        extraJson["filePath"] = fileParam.filePath;
        extraJson["taskId"] = fileParam.taskId;

        // 获取上传链接(非分片文件或分片未上传完才获取上传链接,避免重复获取)
        if (!isChunkFile || totalChunkTime != curChunkTime)
        {
            bool getLink = getUploadLink(fileParam.filePath, fileParam.fileName, extraJson.toStyledString());
            if (!getLink || m_uploadLinkMsg.empty())
            {
                Log_Info("[FileTask][upload] getUploadLink failed. fileName:{}", fileParam.fileName);
                // 获取上传链接失败
                fileUploadStatus(fileParam, FileUpLoadStatus_t::GET_FILE_UPLOAD_LINK_ERROR);
                FileReupload::getInstance().dealUploadResult(fileParam.filePath, -1);
                return;
            }
        }

        // 上传文件
        bool uploadFile = false;
        // 分片是否在合并中
        isMerging = false;

        if (!isChunkFile) // 非分片文件
        {
            uploadFile = doUploadFile();
        }
        else // 分片文件
        {
            uploadFile = doUploadChunkFile();
        }

        // 文件上传成功后,才会上传文件上传结果
        bool uploadFileResult = false;
        if (uploadFile)
        {
            uploadFileResult = uploadResult();
        }

        if (uploadFile && uploadFileResult) // 上传成功
        {
            Log_Info("[FileTask][upload] file upload success. fileName:{}", fileParam.fileName);
            // 上传文件成功
            fileUploadStatus(fileParam, FileUpLoadStatus_t::UPLOAD_FILE_SUCCESS);
            FileReupload::getInstance().dealUploadResult(fileParam.filePath, 0);

            // FC011事件会事件补发,成功后删除记录
            if (!fileup.eventCode.compare("FC011"))
            {
                EventReupload::getInstance().deletEvtReupFile();
            }

            speedStatistics(fileParam.filePath, 2, 0);
            // 谭川那几个法规的事件文件传成功不删，其他传成功删
            removeNoFgDat(fileParam.filePath);
        }
        else if (uploadFile && !uploadFileResult) // 文件上传成功,文件上传结果失败
        {
            Log_Info("[FileTask][upload] file upload result faild. fileName:{}", fileParam.fileName);

            // 发送文件上传结果失败
            fileUploadStatus(fileParam, FileUpLoadStatus_t::SEND_FILE_UPLOAD_RESULT_REQUEST_FAIL);
            FileReupload::getInstance().dealUploadResult(fileParam.filePath, -1);
            speedStatistics(fileParam.filePath, 2, -1);
        }
        else if (!uploadFile && !isMerging) // 上传失败
        {
            Log_Info("[FileTask][upload] file upload faild. fileName:{}", fileParam.fileName);

            // 文件上传响应数据解析失败
            fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_UPLOAD_RESPONSE_DATA_PARSE_FAIL);
            FileReupload::getInstance().dealUploadResult(fileParam.filePath, -1);
            speedStatistics(fileParam.filePath, 2, -1);
        }
        else // 合并中
        {
            Log_Info("[FileTask][upload] filePath:{} is merging...", fileParam.filePath);
        }
    }
}

bool FileTask::getUploadLink(const std::string &filePath, const std::string &fileName, const std::string &extras)
{
    Log_Info(__FUNCTION__);

    std::string url = SRT_HTTPSPRE + comoprhttp.domainHost + SRT_URL_GETFILEUPLOADLINK;
    Log_Info("[http_url] get uploadlink url:{}", url);

    string filemd5str;
    CommonOprOpenssl::GetFile_Md5_Hex(filePath, filemd5str);

    Json::Value parampostFiled;
    parampostFiled["cloudDiskType"] = "CA_Cloud";
    parampostFiled["fileName"] = fileName;
    parampostFiled["fileSize"] = CommonOprSystem::getFileSize(filePath);
    parampostFiled["fileDigest"] = filemd5str;
    parampostFiled["fromSystem"] = "hu";
    parampostFiled["businessType"] = "TerminalLogUpload";
    parampostFiled["extras"] = extras;

    // 若是分片文件调整fileUpType字段
    Json::Value oneFile;
    bool isChunkFile = false;
    if (FileReupload::getInstance().readOneFileJson(fileParam.filePath, oneFile) && oneFile.isMember("isChunkFile"))
    {
        isChunkFile = JsonToValue<bool>(oneFile["isChunkFile"]);
        if (isChunkFile)
        {
            parampostFiled["fileUpType"] = "chunk";
            Log_Info("[FileTask][getUploadLink] file is chunk, filePath: {}", filePath);
        }
    }

    Json::FastWriter writer;
    std::string postFiled = writer.write(parampostFiled);

    // 设置http请求头
    map<string,string> http_header;
    http_header["Content-Type"] = "application/json;charset=UTF-8";
    http_header["Accept"] = "*/*";
    http_header["X-VCS-Hu-Token"] = comoprhttp.hu_tokenMsg;
    http_header["X-VCS-Timestamp"] = CommonOprTime::getTimestr();
    http_header["X-VCS-Nonce"] = CommonOprString::GetRandStr(4);

    std::string responseBuff;
    if (comoprhttp.doHttpPostRequest(url, http_header, postFiled, 1, responseBuff))
    {
        uploadLinkAnalysis(responseBuff);

        // 若是分片文件,将handle存入配置文件中
        if (isChunkFile && !m_uploadTaskIdMsg.empty())
        {
            FileReupload::getInstance().writeFileHandle(filePath, m_uploadTaskIdMsg);
        }
        return true;
    }
    return false;
}

void FileTask::uploadLinkAnalysis(const std::string Jsondata)
{
    Json::Reader reader;
    Json::Value root;
    if (!reader.parse(Jsondata, root))
    {
        Log_Info("[FileTask][uploadLinkAnalysis] json parse error: {}", Jsondata);
        return;
    }
    Json::Value data = root["data"];
    if (data.empty())
    {
        Log_Info("[FileTask][uploadLinkAnalysis] data param is empty: {}", Jsondata);
        return;
    }
    m_uploadLinkMsg = JsonToValue<std::string>(data["uploadLink"]);
    m_uploadTaskIdMsg = JsonToValue<std::string>(data["uploadTaskId"]);
    m_fcToken = JsonToValue<std::string>(data["fcToken"]);
    Json::Value paramList = data["paramList"];
    if (!paramList.isArray())
    {
        return;
    }
    std::string paramName = JsonToValue<std::string>(paramList[0]["paramName"]);
    std::string paramValue = JsonToValue<std::string>(paramList[0]["paramValue"]);

    Log_Info("paramName: {}  paramValue: {}", paramName, paramValue);
    m_headerName = paramName;
    m_headerValue = paramValue;
}

bool FileTask::doUploadFile()
{
    Log_Info("[FileTask][doUploadFile] url: {}", m_uploadLinkMsg);
    std::string responseBuff;
    std::string header = m_headerName + ":" + m_headerValue;

    if (comoprhttp.doHttpUploadFile(responseBuff, m_uploadLinkMsg, m_fcToken, m_headerName, fileParam.filePath, m_headerValue, false))
    {
        bool ret = uploadFileAnalysis(responseBuff);
        return ret;
    }
    else if (CommonOprString::childStrContainCheck(responseBuff, "Timeout was reached")  == DC_SUCC) // 超时特殊上报
    {
        fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_UPLOAD_TIMEOUT_WAS_REACHED);
    }
    return false;
}

bool FileTask::uploadFileAnalysis(const std::string &Jsondata)
{
    Json::Reader reader;
    Json::Value root;
    if (!reader.parse(Jsondata, root))
    {
        Log_Info("[FileTask][uploadFileAnalysis] json parse error: {}", Jsondata);
        return false;
    }
    if (!root.isArray() || root.size() < 1)
    {
        Log_Info("[FileTask][uploadFileAnalysis] root is not array: {}", Jsondata);
        return false;
    }
    m_uploadFileResultMsg = Jsondata;
    Log_Info("[FileTask][uploadFileAnalysis] uploadFileResultMsg: {}", m_uploadFileResultMsg);
    return true;
}

bool FileTask::doUploadChunkFile()
{
    Json::Value oneFile;
    if (!FileReupload::getInstance().readOneFileJson(fileParam.filePath, oneFile))
    {
        Log_Info("[FileTask][doUploadChunkFile] readOneFileJson failed!");
        return false;
    }

    // 判断是否所有分片都上传成功并成功调用了合并接口
    if (!oneFile.isMember("chunkOperation"))
    {
        Log_Info("[FileTask][doUploadChunkFile] read chunkOperation failed!");
        return false;
    }
    bool chunkOperation = JsonToValue<bool>(oneFile["chunkOperation"]);

    // 分片已合并,查询合并结果
    if (chunkOperation)
    {
        bool retCheck = chunkMergedCheckResult(oneFile);
        // 修改分片文件查询合并结果次数
        FileReupload::getInstance().writeQueryTimes(fileParam.filePath);
        return retCheck;
    }

    // 查询curChunkTime和totalChunkTime
    if (!oneFile.isMember("curChunkTime") || !oneFile.isMember("totalChunkTime"))
    {
        Log_Info("[FileTask][doUploadChunkFile] read curChunkTime or totalChunkTime failed! filePath: {}", fileParam.filePath);
        return false;
    }
    int curChunkTime = JsonToValue<int>(oneFile["curChunkTime"]);
    int totalChunkTime = JsonToValue<int>(oneFile["totalChunkTime"]);

    // 若分片未传完,上传分片
    if (curChunkTime < totalChunkTime)
    {
        bool ret = uploadRemainChunk(curChunkTime, totalChunkTime);
        // 删除分片存储文件夹
        std::string cmd = "rm -rf " + global_data::g_split_file_path;
        int retRm = std::system(cmd.c_str());
        if (!ret || retRm != 0)
        {
            Log_Info("[FileTask][doUploadChunkFile] ret = {}, retRm = {}", ret, retRm);
            return false;
        }
    }

    // 所有分片已上传完,调用合并接口
    callMergeInterface();
    // 默认返回false,只有分片合并结果查询成功时才返回true
    return false;
}

bool FileTask::uploadChunkFileAnalysis(const std::string &Jsondata)
{
    Json::Reader reader;
    Json::Value root;
    if (!reader.parse(Jsondata, root))
    {
        Log_Info("parse error: {}", Jsondata);
        return false;
    }

    if (!root.isArray() || root.size() < 1)
    {
        Log_Info("data is not array: {}", Jsondata);
        return false;
    }

    bool ret = JsonToValue<bool>(root[0]["success"]);

    return ret;
}

bool FileTask::uploadResult()
{
    std::string url = SRT_HTTPSPRE + comoprhttp.domainHost + SRT_URL_RESFILEUPLOADRET;
    Log_Info("[http_url] upload result url:{}", url);

    Json::Value parampostFiled;
    parampostFiled["uploadTaskId"] = m_uploadTaskIdMsg;
    parampostFiled["uploadResult"] = m_uploadFileResultMsg;
    Json::FastWriter writer;
    std::string postFiled = writer.write(parampostFiled);

    // 设置http请求头
    map<string, string> http_header;
    http_header["Content-Type"] = "application/json;charset=UTF-8";
    http_header["Accept"] = "*/*";
    http_header["X-VCS-Hu-Token"] = comoprhttp.hu_tokenMsg;
    http_header["X-VCS-Timestamp"] = CommonOprTime::getTimestr();
    http_header["X-VCS-Nonce"] = CommonOprString::GetRandStr(4);

    std::string responseBuff;
    if (!comoprhttp.doHttpPostRequest(url, http_header, postFiled, 1, responseBuff))
    {
        if (CommonOprString::childStrContainCheck(responseBuff, "Timeout was reached")  == DC_SUCC) // 超时特殊上报
        {
            fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_UPLOAD_TIMEOUT_WAS_REACHED);
        }
        Log_Info("[FileTask][uploadResult] fileName : {} upload result timeout!", fileParam.fileName);
        return false;
    }

    Log_Info("[FileTask][uploadResult] responseBuff: {}", responseBuff);
    // 对结果进行判断，有可能是云端负响应导致
    bool retUploadResult = uploadResultAnalysis(responseBuff);
    return retUploadResult;
}

bool FileTask::uploadResultAnalysis(const std::string &Jsondata)
{
    Json::Reader reader;
    Json::Value root;
    if (reader.parse(Jsondata, root) && root.isMember("success"))
    {
        bool ret = JsonToValue<bool>(root["success"]);
        return ret;
    }
    else
    {
        Log_Info("[FileTask][uploadResultAnalysis] json parse error: {}", Jsondata);
    }
    return false;
}

bool FileTask::chunkMergedCheckResult(Json::Value &oneFile)
{
    // 判断查询次数是否超过上限
    if (!oneFile.isMember("queryTimes"))
    {
        Log_Info("[FileTask][doUploadChunkFile] read queryTimes failed!");
        return false;
    }
    int queryTimes = JsonToValue<int>(oneFile["queryTimes"]);

    // 使用totalChunkTime总分片次数作为单次查询最大值
    // 每20MB新增一次查询次数,100MB文件保底查询5次
    if (!oneFile.isMember("totalChunkTime"))
    {
        Log_Info("[FileTask][doUploadChunkFile] read totalChunkTime failed!");
        return false;
    }
    int maxQueryTimes = JsonToValue<int>(oneFile["totalChunkTime"]);

    Log_Info("[FileTask][doUploadChunkFile] queryTimes = {}, maxQueryTimes = {}", queryTimes, maxQueryTimes);

    // 超过查询次数上限,queryTimes置0,保证文件重传时重新查询
    if (queryTimes > maxQueryTimes)
    {
        FileReupload::getInstance().writeQueryTimesToZero(fileParam.filePath);
        isMerging = false;
        return false;
    }

    // 合并中
    isMerging = true;

    if (!oneFile.isMember("fileHandle"))
    {
        Log_Info("[FileTask][doUploadChunkFile] read fileHandle failed!");
        return false;
    }
    string fileHandle = JsonToValue<string>(oneFile["fileHandle"]);

    if (!checkMergeStatus(fileHandle) || !mergeStatusAnalysis(fileParam.filePath, fileHandle))
    {
        return false;
    }

    return true;
}

bool FileTask::checkMergeStatus(const string &fileHandle)
{
    if (fileHandle.empty())
    {
        Log_Info("[FileTask][checkMergeStatus] fileHandle is empty!");
        return false;
    }

    string chunkFileMergeAddr = SRT_HTTPSPRE + comoprhttp.domainHost + SRT_URL_CHUNKFILEMERGERESULTLINK;
    chunkFileMergeAddr += "fileHandle=" + fileHandle;

    Log_Info("[FileTask][checkMergeStatus] chunkFileMergeAddr: {}", chunkFileMergeAddr);

    // 设置http请求头
    map<string, string> http_header;
    http_header["Content-Type"] = "application/json;charset=UTF-8";
    http_header["Accept"] = "*/*";
    http_header["X-VCS-Hu-Token"] = comoprhttp.hu_tokenMsg;
    http_header["X-VCS-Timestamp"] = CommonOprTime::getTimestr();
    http_header["X-VCS-Nonce"] = CommonOprString::GetRandStr(4);

    string responseBuff;
    // 请求方式：get，复用获取配置代码
    if (comoprhttp.getCloudConfig(chunkFileMergeAddr, http_header, responseBuff))
    {
        Json::Reader reader;
        Json::Value root;
        if (reader.parse(responseBuff, root) && root.isMember("success"))
        {
            bool retMergeResult = JsonToValue<bool>(root["success"]);
            return retMergeResult;
        }
    }
    return false;
}

bool FileTask::mergeStatusAnalysis(const string &filePath, const string &fileHandle)
{
    // 文件名
    string fileName = Util::getFileBaseName(filePath);
    if (fileHandle.empty())
    {
        Log_Info("[FileTask][mergeStatusAnalysis] fileHandle is empty!");
        return false;
    }

    m_uploadTaskIdMsg = fileHandle;

    Json::Value root;
    Json::Value uploadResult;
    uploadResult["fileName"] = fileName;
    uploadResult["result"] = fileHandle;
    uploadResult["sucFlag"] = Json::Value(true);

    root.append(uploadResult);
    Json::FastWriter writer;
    m_uploadFileResultMsg = writer.write(root);
    return true;
}

bool FileTask::uploadRemainChunk(const int curChunkTime, const int totalChunkTime)
{
    // 获取需要上传的分片次数(总分片数-当前以分片数)
    int chunkTime = totalChunkTime - curChunkTime;

    for (int i = 0; i < chunkTime; ++i)
    {
        // 文件进行分片分割，返回MD5和文件名
        std::string chunkFilePath = "";
        std::string chunkFileMd5 = "";
        if (!chunkFileSplit(curChunkTime + i, chunkFilePath, chunkFileMd5))
        {
            return false;
        }

        std::string responseBuff;
        std::string header = m_headerName + ":" + m_headerValue;

        // 分片文件上传 请求地址：https://{fileDomain}/fc-apigw/filecloud/api/open/fileup/chunk-file-up?chunkFileMd5=xxx
        std::string all_addr = m_uploadLinkMsg + "?chunkFileMd5=" + chunkFileMd5;
        Log_Info("[FileTask][doHttpUploadFile] all_addr = {} , chunkFilePath = {} ", all_addr, chunkFilePath);

        if (!comoprhttp.doHttpUploadFile(responseBuff, all_addr, m_fcToken, m_headerName, chunkFilePath, m_headerValue, true))
        {
            if (CommonOprString::childStrContainCheck(responseBuff, "Timeout was reached")  == DC_SUCC) // 超时特殊上报
            {
                fileUploadStatus(fileParam, FileUpLoadStatus_t::FILE_UPLOAD_TIMEOUT_WAS_REACHED);
            }
            // 分片上传失败，直接返回失败
            Log_Info("[FileTask][doHttpUploadFile] chunkFilePath : {} upload failed!", chunkFilePath);
            return false;
        }

        // 对结果进行判断，有可能是云端负响应导致
        bool retResult = uploadChunkFileAnalysis(responseBuff);
        if (retResult == false)
        {
            Log_Info("[FileTask][doUploadChunkFile] uploadChunkFileAnalysis failed!");
            return false;
        }

        // 上传成功，更新文件分片信息，删除上传成功的分片文件
        FileReupload::getInstance().writeChunkFileMd5(fileParam.filePath, chunkFileMd5);
        CommonOprSystem::dealTargetFile(chunkFilePath);
    }
    return true;
}

bool FileTask::chunkFileSplit(const int curChunkTime, std::string &chunkFilePath, std::string &chunkFileMd5)
{
    // 文件分割
    std::ifstream in(fileParam.filePath, std::ios::binary);
    if (!in)
    {
        Log_ERROR("[FileTask][chunkFileSplit] file : {} open error!", fileParam.filePath);
        return false;
    }
    // 从文件首部移动文件指针
    in.seekg(global_data::g_per_chunk_size * curChunkTime, std::ios::beg);

    if (!CommonOprSystem::isPathExist(global_data::g_split_file_path))
    {
        int ret = mkdir(global_data::g_split_file_path.c_str(), S_IRWXU);
        (void)ret;
    }

    // 文件命名 /ds/fileChunk/{curChunkTime}_{fileName}
    chunkFilePath = global_data::g_split_file_path + std::to_string(curChunkTime) + '_' + fileParam.fileName;

    std::ofstream out(chunkFilePath, std::ios::binary);
    if (!out)
    {
        Log_ERROR("[FileTask][chunkFileSplit] file : {} open error!", chunkFilePath);
        return false;
    }

    std::vector<char> fileBuffer(global_data::g_per_chunk_size);

    in.read(fileBuffer.data(), global_data::g_per_chunk_size);
    out.write(fileBuffer.data(), in.gcount());

    // 文件关闭
    in.close();
    out.close();

    // 分片文件MD5码
    CommonOprOpenssl::GetFile_Md5_Hex_Lower(chunkFilePath, chunkFileMd5);

    if (chunkFilePath.empty() || chunkFileMd5.empty())
    {
        Log_Info("[FileTask][chunkFileSplit] chunkFilePath :{} || chunkFileMd5: {} is empty", chunkFilePath, chunkFileMd5);
        return false;
    }

    return true;
}

void FileTask::callMergeInterface()
{
    Json::Value oneFile;

    if (!FileReupload::getInstance().readOneFileJson(fileParam.filePath, oneFile))
    {
        Log_Info("[FileTask][doUploadChunkFile] readOneFileJson failed!");
        return;
    }

    // 查询异步合并所需文件信息
    MergeParam mergeParam;
    if (!mergeParamAnalysis(oneFile, mergeParam))
    {
        return;
    }
    mergeParam.filePath = fileParam.filePath;
    mergeParam.fileName = fileParam.fileName;

    if (chunkFileMerge(mergeParam))
    {
        isMerging = true;
    }
}

bool FileTask::mergeParamAnalysis(Json::Value &oneFile, MergeParam &mergeParam)
{
    if (!oneFile.isMember("fileMd5") || !oneFile.isMember("fileHandle") || !oneFile.isMember("fileMd5Arrary") || !oneFile["fileMd5Arrary"].isArray())
    {
        Log_Info("[FileTask][mergeParamAnalysis] mergeParamAnalysis failed!");
        return false;
    }
    string fileMd5 = JsonToValue<string>(oneFile["fileMd5"]);
    string fileHandle = JsonToValue<string>(oneFile["fileHandle"]);
    Json::Value fileMd5Arrary = oneFile["fileMd5Arrary"];
    string chunkFileMd5 = "";
    int i = 0;
    for (; i < fileMd5Arrary.size() - 1; ++i)
    {
        chunkFileMd5 += JsonToValue<string>(fileMd5Arrary[i]);
        chunkFileMd5 += ',';
    }
    chunkFileMd5 += JsonToValue<string>(fileMd5Arrary[i]);

    mergeParam.chunkFileMd5 = chunkFileMd5;
    mergeParam.fileMd5 = fileMd5;
    mergeParam.fileHandle = fileHandle;
    return true;
}

bool FileTask::chunkFileMerge(MergeParam &mergeParam)
{
    // 分片文件异步合并 请求地址：https://{fileDomain}/fc-apigw/filecloud/api/open/fileup/chunk-file-merge?chunkFileMd5=xx&fileMd5=x&fileHandle=x&fileName=x
    Log_Info("[FileTask] [chunkFileMerge] start");
    std::string chunkFileMergeAddr = SRT_HTTPSPRE + comoprhttp.domainHost + SRT_URL_CHUNKFILEASYNMERGELINK;
    chunkFileMergeAddr += "chunkFileMd5=" + mergeParam.chunkFileMd5;
    chunkFileMergeAddr += "&fileMd5=" + mergeParam.fileMd5;
    chunkFileMergeAddr += "&fileHandle=" + mergeParam.fileHandle;
    chunkFileMergeAddr += "&fileName=" + mergeParam.fileName;

    Log_Info("[FileTask][chunkFileGet] chunkFileMergeAddr: {}", chunkFileMergeAddr);

    // 设置http请求头
    map<string, string> http_header;
    http_header["Content-Type"] = "application/json;charset=UTF-8";
    http_header["Accept"] = "*/*";
    http_header["X-VCS-Hu-Token"] = comoprhttp.hu_tokenMsg;
    http_header["X-VCS-Timestamp"] = CommonOprTime::getTimestr();
    http_header["X-VCS-Nonce"] = CommonOprString::GetRandStr(4);

    std::string responseBuff;

    // 分片文件异步合并，请求方式：get，复用获取配置代码
    if (comoprhttp.getCloudConfig(chunkFileMergeAddr, http_header, responseBuff))
    {
        Json::Reader reader;
        Json::Value rootMerge;
        if (reader.parse(responseBuff, rootMerge) && rootMerge.isMember("success"))
        {
            bool retMerge = JsonToValue<bool>(rootMerge["success"]);
            if (retMerge)
            {
                // 异步合并操作执行成功，chunkOperation置为true
                FileReupload::getInstance().writeChunkOperation(mergeParam.filePath);
                
                Log_Info("[FileTask][chunkFileMerge] success");
                return true;
            }  
        }
    }

    Log_Info("[FileTask][chunkFileMerge] failed, responseBuff: {}", responseBuff);
    return false;
}
